#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define INSTR_SIZE 10
#define REG_MAX 255
#define REG_WIDTH 8
#define PROGRAM_MEM_SIZE 8192
#define MNEMONIC_SIZE 10
#define CONFIG_WORD_SIZE 14
#define MEM_WIDTH 14
#define FILE_CHARS 80
#define MAX_CRASHES 1
#define NUM_OF_PGM_RUNS 10
#define NUM_OF_INSTR 395
#define CLOCKS_PER_INSTR 4
#define PROBABILITY_INVERSE 150
#define RANDOM_GUESS_RANGE 101
#define INSTR_CYCLES_NUMBER 10000
#define NUM_OF_BITFLIPS 10000
#define PC_MATRIX_MULT_RANGE 2000
#define HAMMING_WIDTH 14
#define PARITY_WIDTH 7

/*
#define DEBUG
#ifdef DEBUG
#define PRINT printf
#else
 #define PRINT print_null
#endif
*/

#define DEBUG
 #define PRINT print_null


void print_null (char* n,...) {return;}
unsigned int previous_time = -1;
//All declarations

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct registers
{
    int GP_Reg[REG_MAX]; //General purpose register file map 255 locations accessed through reg_index or reg_file_addr
    int W; //Accumulator/ W register
    int PC; //13-bit Program counter. Can address max 8k x 14 memory space- actual value derived from PCL and PCLATH
    //int status_reg[REG_WIDTH];
    //int option_reg[REG_WIDTH];
    //int INTCON_reg[REG_WIDTH];
    //int EECON1_reg[REG_WIDTH];
    int configuration_word[CONFIG_WORD_SIZE]; //Actually each bit has been configured as an int byte
    int WDT; //8 bit wide
    int WDT_prescaler; //8-bit counter
    int stack[REG_WIDTH]; //8-level deep stack of 13-bit wide. Max number to enter is 8192
    int stack_pointer; //max length = 8
    int PCLATH; //8 bit register -- actual value taken from GP_Reg
    int PCL;//8 bit register- actual value taken from GP_Reg
	int initial_PCL;
	int initial_PCLATH;
	int  starting_PC_value;
	int max_instr;
	int instruction;
	int PC_array_for_matrix_mult[PC_MATRIX_MULT_RANGE];
	int max_PC_count_matrix_mult;
	int instr_array_for_matrix_mult[PC_MATRIX_MULT_RANGE];
	int minPC;
	int Last_valid_PC;
	int duplicate_matrix_mult[PC_MATRIX_MULT_RANGE];

//For hamming code
	int GP_Reg_encoded[REG_MAX]; //Hamming encoded: General purpose register file map 255 locations accessed through reg_index or reg_file_addr
	int hamming_code[HAMMING_WIDTH];
	int parity[PARITY_WIDTH];
	int initial_PCL_encoded;
	int initial_PCLATH_encoded;
	int PCLATH_encoded; //8 bit register -- actual value taken from GP_Reg
    int PCL_encoded;//8 bit register- actual value taken from GP_Reg
	int temp_PC;
	int PC_encoded;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

enum Mnemonic
{

//Specific opcodes
    SLEEP,
    CLRWDT,
    RETURN,
    RETFIE,
//Byte-oriented instructions    
    NOP,
    MOVWF,
    CLRW,
    CLRF,
    SUBWF,
    DECF,
    IORWF,
    ANDWF,
    XORWF,
    ADDWF,
    MOVF,
    COMF,
    INCF,
    DECFSZ,
    RRF,
    RLF,
    SWAPF,
    INCFSZ,
//Bit-oriented instructions
    BCF,
    BSF,
    BTFSC,
    BTFSS,
//Literal and control instructions
    MOVLW,
    RETLW,
    IORLW,
    ANDLW,
    XORLW,
    SUBLW,
    ADDLW,
//Call and goto instructions
    CALL,
    GOTO
        
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct instructions
{
    int instruction;
    int opcode;
    int reg_file_addr;
    int d;
    int reg_index;
    int bit;
    int immediate_value;
    char instr_mnemonic[MNEMONIC_SIZE];
    enum Mnemonic instr_mnemonic_enum; 
	int decode_bits;     
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct crash_parameters
{

	int random_number;
	int random_reg[NUM_OF_BITFLIPS];
	int random_mem[NUM_OF_BITFLIPS];
	unsigned long long int instr_cycles,instr_cycles_for_error;
	int random_choose;
	int crash;
	unsigned long long int crash_at_instr[MAX_CRASHES]; // Store the number of clock cycles at which each time a crash occurs
	unsigned long long int errors_repeated[NUM_OF_BITFLIPS];
	long int crash_time_array[MAX_CRASHES];
	long int actual_crash_time_array[MAX_CRASHES];
	unsigned long long int program_runs;
	int crash_dueto_illegal_mem;
	int crash_dueto_PC;
	int crash_dueto_illegal_opcode;
	int first_error;
	int control_flow_change;
	unsigned long long int first_error_at_instr[INSTR_CYCLES_NUMBER];
	unsigned long long int rest_of_the_errors[INSTR_CYCLES_NUMBER];
	unsigned long long int incorrect_data;
	int incorrect_data_in_instr;
	int flip_bit_flag;
	int reg_count;
	int mem_count;
	int store_same_reg_modification[NUM_OF_BITFLIPS];
	int same_reg;
	int store_PC_same[NUM_OF_BITFLIPS];
	int same_PC;
	int reg_index_match;
	int set_no_same_PC;
	int crash_mem_access;
	int opcode_count;
	int random_bit_mem;
	int opcode_change;
	int crash_reg_index;
	int erroneous_instruction;
	int flip_bit_flag_for_illegal_inst;
	int incorrect_data_flag;
	int errors_so_far;
	int other_errors;
	int just_reset_PC_after_crash;
	int bit_flipped;

//hamming
	int single_error_corrected;
	int double_error_detected;
	int double_error;
	int crash_avoided;
	unsigned long long int crash_avoided_at_instr[MAX_CRASHES]; // Store the number of clock cycles at which each time a crash occurs
	long int crash_avoided_time_array[MAX_CRASHES];

};



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Function declarations
int read_instr_from_file(FILE *,int program_memory[],struct registers *, FILE *);

int	read_PC_array_for_matrix_mult(FILE *, int program_memory[], struct registers * , FILE *);
int	read_instr_for_matrix_mult(FILE *, int program_memory[],int[], struct registers *, FILE *);


int instruction_fetch(struct registers *r, int program_memory[],int program_memory_encoded[], struct crash_parameters *cp,FILE *fnew, time_t start_seconds,struct instructions *i1,  FILE *fPC, FILE *finstr);
//int instruction_fetch_matrix_mult(struct registers *r, int program_memory[],struct crash_parameters *cp, FILE *);


int PC_increment(struct registers *r, FILE *fnew,  struct crash_parameters *cp, int program_memory[],int  program_memory_encoded[],  time_t start_seconds,struct instructions *i1,  FILE *fPC, FILE *finstr);
//int increment_PC_double_pointer(struct registers **);
int increment_PC(struct registers *r, FILE *fnew, struct crash_parameters *cp,  int program_memory[],int  program_memory_encoded[],  time_t start_seconds,struct instructions *i1,  FILE *fPC, FILE *finstr);

int reset_PC_to_beginninng(struct registers *r, FILE *fnew, struct crash_parameters *cp,  int program_memory[],int  program_memory_encoded[],  time_t start_seconds,struct instructions *i1,  FILE *fPC, FILE *finstr);
int initialise_regs(struct registers*);
int initialise_crash_param(struct crash_parameters *);

int instruction_decode(struct registers *, struct instructions *, int[] ,struct crash_parameters *, FILE *, FILE *, time_t start_seconds);
int instruction_decode_matrix_mult(struct registers *r1, struct instructions *i1, int program_memory[], int [], struct crash_parameters *cp, FILE *, FILE *, FILE*, time_t start_seconds);

int decode_byte_instr(struct instructions *i1,struct crash_parameters *,struct registers *, int [], int[], FILE *, FILE *, FILE *, time_t start_seconds);
int decode_bit_instr(struct registers *, struct instructions *i1, struct crash_parameters *, FILE *, FILE *, FILE *,time_t start_seconds, int[], int[]);
int literal_control_instr(struct registers *, struct instructions *i1, struct crash_parameters *, FILE *, FILE *, FILE *, time_t start_seconds, int[], int[]);
int call_goto_instr(struct registers *, struct instructions *i1, struct crash_parameters *, FILE *, FILE *,FILE *, time_t start_seconds, int[], int[]);



int instruction_execute(struct registers *, struct instructions *, int [], int [], struct crash_parameters *, FILE *, FILE *, FILE *, time_t start_seconds);
int push(struct registers *);
int pop (struct registers *);

int bit_flips(struct registers *, int [],int[], struct crash_parameters *, time_t, struct instructions *, FILE *, FILE *, FILE *,FILE *, FILE *);
int check_pgm_crash(struct crash_parameters *, time_t, struct registers*);
int check_pgm_error(struct crash_parameters *cp, struct registers *r2, struct instructions *i1, int program_memory[], int program_memory_encoded[], FILE *fnew, FILE *fPC, FILE *finstr, time_t start_seconds);

int check_illegal_instr(struct registers *,  int [], int[], struct crash_parameters *, time_t ,struct instructions *, FILE *, FILE *, FILE *);


int report_crash_avoided(struct registers *,  int program_memory[], int [], struct crash_parameters *, time_t start_seconds,struct instructions *, FILE *, FILE *, FILE *);

int report_crash_and_reset(struct registers *r2,  int program_memory[],int  program_memory_encoded[], struct crash_parameters *cp, time_t start_seconds,struct instructions *i1, FILE *fnew, FILE *fPC, FILE *finstr);
	
int handle_byte_instruction_error(struct registers *r2,int program_memory[], int [], struct crash_parameters *cp,time_t start_seconds,struct instructions *i1,FILE *,FILE *, FILE *);

	
int handle_bit_instruction_error(struct registers *r2,int program_memory[], int [], struct crash_parameters *cp,time_t start_seconds,struct instructions *i1,FILE *,FILE *, FILE *);

int handle_literal_instruction_error(struct registers *r2,int program_memory[], int [], struct crash_parameters *cp,time_t start_seconds,struct instructions *i1,FILE *,FILE *, FILE *);

int reset_instruction_after_crash(struct instructions *i1);
int report_error(struct crash_parameters *, struct registers *, struct instructions *, int program_memory[], FILE *);
int reset_after_crash(struct registers *,  int program_memory[], int[], struct crash_parameters *, time_t start_seconds, FILE *, FILE *, FILE *, struct instructions *i1);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//----------------------------------------Function definitions---------------------------------------------------------//
int initialise_regs(struct registers *r)
{
	int i=0;
	printf("Initialising all registers\n");
		r->max_instr=0;
		r->instruction=0;
	//Max register content= 255 (dec) or FF (hex)
        r->configuration_word[11]= 1; //WDT Enabler bit
		r->starting_PC_value=0;
//clear all registers
			for(i=0;i<REG_MAX;++i)
                r->GP_Reg[i]=0; //clear all registers in register file map
       
        //INTCON Register
                r->GP_Reg[0x0B]=0; //INTCON register at address 0B in the register file map
                r->GP_Reg[0x8B]= r->GP_Reg[0x0B];

        //for(i=0;i<MEM_WIDTH;++i)
        //      r->PC=0;
        //STACK
                r->stack_pointer = 0;
               // r->stack[1] = 0x62;
               // r->stack[0] = 0x88;
			
		for(i=0;i<REG_WIDTH;++i)
                r->stack[i]=0; 


        // Status register = GP_Reg[3]
        //Assigning some value to the carry in status reg
//              r->GP_Reg[3]= r->GP_Reg[3] & 0xFE; //carry = 0
                //r->GP_Reg[3]= r->GP_Reg[3] | 0x01; //carry = 1
                r->GP_Reg[3]= 0x00;
                r->GP_Reg[0x83]= r->GP_Reg[3]; //Bank 1 and Bank 0

                r->W = 0x00;
               
        //TMRO
                r->GP_Reg[1]= 0x00;

        //OPTION REG
                r->GP_Reg[0x81]= 0x00;

                //FSR
                r->GP_Reg[4]= 0x00;
                r->GP_Reg[0x84]= r->GP_Reg[4];

        //PORTA
                r->GP_Reg[5]= 0x00;

        //PORTB
                r->GP_Reg[6]= 0x00;

        //TRISA
                r->GP_Reg[0x85]= 0x00;

        //TRISB
                r->GP_Reg[0x86]= 0x00;

        //EEDATA
                r->GP_Reg[8]= 0x00;

        //EEADR
                r->GP_Reg[9]= 0x00;

        //EECON1
                r->GP_Reg[0x88]= 0x00;

        //EECON2 - not a physical register
        //      r->GP_Reg[0x89]= 0x00;

//Initialise PC values
				 r->initial_PCL =0;
				  r->initial_PCLATH=0;

//use this address 0x02 to write into PCL:
//PCL= GP_Reg[2] and GP_Reg[0x82]
                r->GP_Reg[2]= 0x00;
                r->GP_Reg[0x82]= r->GP_Reg[2]; //Bank 1 and Bank 0
                r->PCL= r->GP_Reg[2];

        //PCLATH.. use this address to write into PCLATH
                r->GP_Reg[0x0A]= 0x00;
                r->GP_Reg[0x8A]= r->GP_Reg[0x0A]; //Bank 1 and Bank 0
                r->PCLATH= r->GP_Reg[0x0A];

                r->PC = (r->PCL | (r->PCLATH << 8)) & 0x1FFF; //Limit to 13 bits. Program counter is 13 bits

				//Parameters for matrix multiplication
				
				for(i=0;i<PC_MATRIX_MULT_RANGE;++i)
	                r->PC_array_for_matrix_mult[i]=0;

				for(i=0;i<PC_MATRIX_MULT_RANGE;++i)
	                r->instr_array_for_matrix_mult[i]=0;

				for(i=0;i<PC_MATRIX_MULT_RANGE;++i)
	                r->duplicate_matrix_mult[i]=0;
		


				r->minPC=0;
				r->max_PC_count_matrix_mult=0;
				r->Last_valid_PC=0;

//Hamming
			for(i=0;i<REG_MAX;++i)
                r->GP_Reg_encoded[i]=0; //Hamming encoded Reg file map: clear all registers in register file map

			for(i=0;i<HAMMING_WIDTH;++i)
	                r->hamming_code[i]=0;

			for(i=0;i<PARITY_WIDTH;++i)
	                r->parity[i]=0;


			r->initial_PCL_encoded =0;
			r->initial_PCLATH_encoded=0;
			r->temp_PC=0;
			r->PC_encoded=0;


            PRINT("-----------------------------------------------------------------\n");
            PRINT("Initial values (hex): PCL=%x, PCLATH=%x, PC(testing) = %x \n",r->PCL, r->PCLATH, r->PC);

return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int initialise_crash_param(struct crash_parameters *cp)
{
	int i=0;
	printf("Initialising crash parameters\n");
		cp->random_number=0;
		cp->random_bit_mem=0;
		cp->reg_count=0;
		cp->mem_count=0;
		cp->instr_cycles=0;
		cp->instr_cycles_for_error=0;
		cp->crash=0;
		cp->program_runs=0;
		cp->crash_dueto_illegal_mem=0;
		cp->crash_dueto_PC=0;
		cp->crash_dueto_illegal_opcode=0;
		cp->first_error=0;
		cp->control_flow_change=0;
		cp->incorrect_data=0;
		cp->incorrect_data_in_instr=0;
		cp->same_reg=0;
		cp->same_PC=0;
		cp-> reg_index_match=0;
		cp->set_no_same_PC=1; // for the very first PC
		cp->crash_mem_access = 0;
		cp->opcode_count =0;
		cp->opcode_change=0;
		cp->crash_reg_index=0;
		cp->erroneous_instruction=0;
		cp->flip_bit_flag_for_illegal_inst=0;
		cp->incorrect_data_flag=0;
		cp->other_errors=0;
		cp->errors_so_far=0;
		cp->random_choose=0;
		cp->just_reset_PC_after_crash=0;
		cp->bit_flipped = 0;

		//clear all locations
			for(i=0;i<NUM_OF_BITFLIPS;++i)
                cp->store_PC_same[i]=0;
			
			for(i=0;i<MAX_CRASHES;++i)
                cp->crash_at_instr[i]=0;
			
			for(i=0;i<MAX_CRASHES;++i)
                cp->crash_time_array[i]=0;
			
			for(i=0;i<MAX_CRASHES;++i)
                cp->actual_crash_time_array[i]=0;

			for(i=0;i<INSTR_CYCLES_NUMBER;++i)
                cp->first_error_at_instr[i]=0;

			for(i=0;i<INSTR_CYCLES_NUMBER;++i)
                cp->rest_of_the_errors[i]=0;
	
			for(i=0;i<NUM_OF_BITFLIPS;++i)
                cp->random_reg[i]=0;

			for(i=0;i<NUM_OF_BITFLIPS;++i)
                cp->random_mem[i]=0;

			for(i=0;i<NUM_OF_BITFLIPS;++i)
                cp->store_same_reg_modification[i]=0;


//hamming
		cp-> single_error_corrected=0;
		cp-> double_error_detected=0;
		cp->double_error=0;
		cp->crash_avoided=0;
return 0;
}



int reset_instruction_after_crash(struct instructions *i1)
{

	i1->instruction=0;
    i1->opcode=0;
    i1->reg_file_addr=0;
    i1->d=0;
    i1->reg_index=0;
    i1->bit=0;
    i1->immediate_value=0;
   	i1->decode_bits;  
	i1->instr_mnemonic_enum = NOP;

return 0;

}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*int read_instr_from_file(FILE *fp, int program_memory[], struct registers *r, FILE *fnew)
{ //this is for add program only, not for matrix multiplication

	int i=0;
    char line[FILE_CHARS]; 
    //int starting_PC_value = 0;
	int instr_from_file=0;

	reset_PC_to_beginninng(r, fnew); //Initial PC values are set in this function
		
 		r->max_instr= r->PC; // new value of max_instr is initialised to the PC value that is read from the disassembly listing
        r->starting_PC_value = r->PC;
        PRINT("Starting PC value=%x\n",r->starting_PC_value);

		fp= fopen("simple_add_assembly.c","rt");
        if( fp == NULL )
         {
               puts ( "cannot open file" ) ;
          //     exit(0) ;
         }  

		while(fgets(line, FILE_CHARS, fp) != NULL)
           {
                // get a line, up to 80 chars from fp.  done if NULL 
                sscanf (line, "%x", &instr_from_file);
                program_memory[r->max_instr]= instr_from_file;
                r->max_instr = (r->max_instr) + 1; //max_instr indicates the max instructions
               
           }
         
		printf("\nLoading instructions to memory\n");
		fprintf(fnew,"\nLoading instructions to memory\n");

        for(i= r->starting_PC_value;i< (r->max_instr);i++)
        {
		    printf("Instructions read from file= program_memory[%x]= %x\n",i, program_memory[i]);
			fprintf(fnew,"Instructions read from file= program_memory[%x]= %x\n",i, program_memory[i]);
		}

	printf("Maximum number of instructions in the program is: %d\n\n", r->max_instr);
	fprintf(fnew,"Maximum number of instructions in the program is: %d\n\n", r->max_instr);


	fclose(fp);  // close the file prior to exiting the function
	
return 0;

}

*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int	read_PC_array_for_matrix_mult(FILE *fPC, int program_memory[], struct registers *r , FILE *fnew)
{ //Read PC values for matrix multiplication

	int i=0;
    char line[FILE_CHARS]; 
    //int starting_PC_value = 0;
	int PC_for_matrix_mult=0;

	//reset_PC_to_beginninng(r,fnew); //Initial PC values are set in this function
		

	fPC = fopen( "matrix_assembly_PConly.c", "rt" );

    if( fPC == NULL )
     {
           puts ( "cannot open file matrix_assembly_PConly.txt" ) ;
           exit(0) ;
     }  

	printf("r->max_PC_count_matrix_mult= %x before resetting\n",r->max_PC_count_matrix_mult);

	r->max_PC_count_matrix_mult=0;

	while(fgets(line, FILE_CHARS, fPC) != NULL)
       {
            // get a line, up to 80 chars from file.  done if NULL 
            sscanf (line, "%x", &PC_for_matrix_mult);
            r->PC_array_for_matrix_mult[r->max_PC_count_matrix_mult]= PC_for_matrix_mult;
            r->max_PC_count_matrix_mult = (r->max_PC_count_matrix_mult) + 1; //indicates max PC count
           
       }
     
	//printf("\nPC values read are: \n");
	//fprintf(fnew,"\nPC values read are: (in hex) \n");

   /* for(i= 0; i< r->max_PC_count_matrix_mult; i++)
    {
	     PRINT("PC_value[%x]= %x\n",i, r->PC_array_for_matrix_mult[i]);
		//fprintf(fnew,"PC_value[%x]= %x\n",i, r->PC_array_for_matrix_mult[i]);
	}*/

	printf("Maximum number of instructions in the program is: %d\n\n", r->max_PC_count_matrix_mult);
	fprintf(fnew,"Maximum number of instructions in the program is: %d\n\n", r->max_PC_count_matrix_mult);

	r->max_instr = r->max_PC_count_matrix_mult; //Max instruction count
	r->Last_valid_PC = r->PC_array_for_matrix_mult[0] + r->max_instr;

	printf("r->max_PC_count_matrix_mult=%x\n",r->max_PC_count_matrix_mult);
	printf("r->PC_array_for_matrix_mult[0]=%x\n",r->PC_array_for_matrix_mult[0]);
	printf("r->max_instr= %x\n\n", r->max_instr);
	printf("Last valid PC value is (in hex): %x\n\n", r->Last_valid_PC -1);
	fprintf(fnew,"Last valid PC value is (in hex): %x\n\n", r->Last_valid_PC -1);


	fclose(fPC);  // close the file prior to exiting the function
	//exit(0);

return 0;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



int	read_instr_for_matrix_mult(FILE *finstr, int program_memory[],int program_memory_encoded[], struct registers *r, FILE *fnew)
{//Read instruction for matrix multiplication

	int i=0, j=0, count=0;
    char line[FILE_CHARS]; 
 	int instr_for_matrix_mult=0;
	fprintf(fnew,"Loaded matrix multiplication program into memory\n\n");

		
	finstr = fopen( "matrix_assembly_instruction_only.c", "rt" );

    if( finstr == NULL )
     {
           puts ( "cannot open file matrix_assembly_instruction_only.txt" ) ;
           exit(0) ;
     }  
	fprintf(fnew,"Instructions read as is, from the file.. not according to increasing order of PC\n");

	while(fgets(line, FILE_CHARS, finstr) != NULL)
       {
            
			// get a line, up to 80 chars from file.  done if NULL 
            sscanf (line, "%x", &instr_for_matrix_mult);

//working.. using complicate method of fetching using array index
       		// r->instr_array_for_matrix_mult[j]= instr_for_matrix_mult;
		    //  program_memory[j]= instr_for_matrix_mult;


//Uses simple fetch()
			count= r->PC_array_for_matrix_mult[j]; //PC value
            r->instr_array_for_matrix_mult[count]= instr_for_matrix_mult; //Store the instruction at the array index=PC value
		    program_memory_encoded[count]= hamming_encoding_14bit(instr_for_matrix_mult); //encode the instruction
		
			//fprintf(fnew,"program_memory_encoded[PC=%x]: %x\n", count, program_memory_encoded[count]);

			j++; 
           
       }
 
		fprintf(fnew,"\n\n");
	
  /*  for(i= 0; i< r->max_PC_count_matrix_mult; i++)
    {
	   // printf("Instruction[%x]= %x\n",r->PC_array_for_matrix_mult[i], program_memory[r->PC_array_for_matrix_mult[i]]);
		fprintf(fnew,"Instruction[%x]= %x\n",r->PC_array_for_matrix_mult[i], program_memory[r->PC_array_for_matrix_mult[i]]);
	}

	printf("\nInstructions in increasing PC order are: \n");
	fprintf(fnew,"\nInstructions in increasing PC order are: \n");

	r->minPC=r->PC_array_for_matrix_mult[0]; //The minimum PC value.. This is not necessarily the starting PC value for program execution

	printf("THe first PC content i %x\n",r->minPC);
	fprintf(fnew,"THe first PC content i %x\n",r->minPC);

	/* for(i= 0; i< r->max_PC_count_matrix_mult; i++)
    {
	    //printf("program_memory[%x]= %x\n",r->minPC, program_memory[r->minPC]);
		fprintf(fnew,"program_memory[%x]= %x\n",r->minPC, program_memory[r->minPC]);
		r->minPC++;
	}


	printf("\nMaximum number of instructions in the program is: %d\n\n", r->max_PC_count_matrix_mult);
	fprintf(fnew,"\nMaximum number of instructions in the program is: %d\n\n", r->max_PC_count_matrix_mult);*/


	fclose(finstr);  // close the file prior to exiting the function

return 0;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int reset_PC_to_beginninng(struct registers *r, FILE *fnew, struct crash_parameters *cp,   int program_memory[],int  program_memory_encoded[],  time_t start_seconds,struct instructions *i1,  FILE *fPC, FILE *finstr)
{
	int temp=0;


//----------------------------------------------------------------------------------------------------------------------------
        //Reset program counter to beginning of the program
        temp = error_detect_correct_decode(r->initial_PCL_encoded, fnew, cp, r,program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr ); //decode initial PCL
		r->GP_Reg_encoded[2] = hamming_encoding(temp);
		r->GP_Reg[2] = error_detect_correct_decode(r->GP_Reg_encoded[2], fnew, cp, r,program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr);
        r->GP_Reg[0x82]= r->GP_Reg[2]; //PCL Bank 1 and Bank 0
        r->PCL= r->GP_Reg[2];

        temp = error_detect_correct_decode(r->initial_PCLATH_encoded, fnew, cp, r,program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr); //decode initial PCL
		r->GP_Reg_encoded[0x0A] = hamming_encoding(temp);
		r->GP_Reg[0x0A] = error_detect_correct_decode(r->GP_Reg_encoded[0x0A], fnew, cp, r,program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr);
	    r->GP_Reg[0x8A]= r->GP_Reg[0x0A]; //PCLATH Bank 1 and Bank 0
        r->PCLATH= r->GP_Reg[0x0A];

        r->PC = (r->PCL | (r->PCLATH << 8)) & 0x1FFF; //Limit to 13 bits. PC= 13 bits
        //----------------------------------------------------------------------------------------------------------------------------

		PRINT("reset_PC to_beginninng(): PC is reset to its initial values (in hex): PCL=%x, PCLATH=%x, PC=%x\n",r->PCL, r->PCLATH, r->PC);
//		fprintf(fnew,"reset_PC to_beginninng: PC is reset to its initial values (in hex): PCL=%x, PCLATH=%x, PC=%x\n",r->PCL, r->PCLATH, r->PC);

return 0;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int instruction_fetch(struct registers *r, int program_memory[],int program_memory_encoded[], struct crash_parameters *cp,FILE *fnew, time_t start_seconds,struct instructions *i1,  FILE *fPC, FILE *finstr)
{

	PRINT("-------------------------------------------------------------------\n");
  //  printf("INSTRUCTION FETCH >>\n");

		program_memory[r-> PC]= error_detect_correct_decode_14bit_inside_fetch(program_memory_encoded[r-> PC], fnew, cp, r,program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr);
    r-> instruction = program_memory[r-> PC];
    

//encode and write it back                                        
program_memory_encoded[r-> PC]= hamming_encoding_14bit(program_memory[r-> PC]);

//encode and write back- checking


  //   printf("CLOSING INSTRUCTION FETCH >>\n");

    PRINT("Current PC: PCL=%x, PCLATH=%x, PC = %x \n",r->PCL,r->PCLATH, r->PC);
	PRINT("Instruction fetched is:\n");
	//fprintf(fnew,"Instruction fetched is:\n");

	PRINT("program_memory[%x]=%x\n",r->PC, program_memory[r->PC]);

    PRINT("-------------------------------------------------------------------\n");
    return 0;
        
}                       

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


int PC_increment(struct registers *r, FILE *fnew,  struct crash_parameters *cp, int program_memory[],int  program_memory_encoded[],  time_t start_seconds,struct instructions *i1,  FILE *fPC, FILE *finstr)
{

	PRINT("To increment PC\n");
	//Increment PC
    increment_PC(r, fnew, cp, program_memory, program_memory_encoded,start_seconds, i1, fPC, finstr );
	PRINT("After Incrementing PC: PCL=%x, PCLATH=%x, PC = %x \n",r->GP_Reg[2],r-> GP_Reg[0x0A], r->PC);
	
	return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int increment_PC(struct registers *r, FILE *fnew, struct crash_parameters *cp,  int program_memory[],int  program_memory_encoded[],  time_t start_seconds,struct instructions *i1,  FILE *fPC, FILE *finstr)
{

int temp_PCLATH=0, temp_PCL=0;


temp_PCL = error_detect_correct_decode( r-> GP_Reg_encoded[2], fnew, cp, r, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr )  ; //decoded PCL 
//PRINT("temp_PCL=%x\n", temp_PCL);

	if (temp_PCL == 0xFF)
	{
	//Increment PCLATH once PCL reaches 0xFF

	//Decode the encoded PCLATH and increment it
		temp_PCLATH = error_detect_correct_decode( r-> GP_Reg_encoded[0x0A],fnew, cp, r, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr )  ; //decoded PCLATH i.e., 0x0A location 
		temp_PCLATH = temp_PCLATH + 1; 
	
	//Encode the incremented PCLATH and write it back
		r-> GP_Reg_encoded[0x0A]= hamming_encoding(temp_PCLATH);
		//r-> GP_Reg[0x0A] = r-> GP_Reg[0x0A] + 1; //Increment PCLATH
	}


//PCL= GP_Reg[2] and GP_Reg[0x82]
		temp_PCL= (temp_PCL + 1) & 0xFF; //Increment and limit PCL to 8 bits only
		//PRINT("Incremented temp_PCL: %x\n", temp_PCL);

//Encode the incremented PCL and write it back
		r-> GP_Reg_encoded[2]= hamming_encoding(temp_PCL);
		//PRINT("Encoded GP_Reg[2]: %x\n",r-> GP_Reg_encoded[2]);
		r-> GP_Reg_encoded[0x82]= r-> GP_Reg_encoded[2]; //Bank 1 and Bank 0
        r-> PCL_encoded= r-> GP_Reg_encoded[2];

		
//old code
		// r-> GP_Reg[2]= (r-> GP_Reg[2] + 1) & 0xFF; //Limit PCL to 8 bits only
        //r-> GP_Reg[0x82]= r-> GP_Reg[2]; //Bank 1 and Bank 0

	//PRINT("\nDecoding content in 0x0A\n");
//PCLATH
        temp_PCLATH = error_detect_correct_decode( r-> GP_Reg_encoded[0x0A],fnew, cp, r, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr)  ; //decoded PCLATH i.e., 0x0A location 

		//PRINT("temp_PCLATH decoded=%x\n", temp_PCLATH);
		r-> GP_Reg_encoded[0x8A]= r-> GP_Reg_encoded[0x0A]; //Bank 1 and Bank 0
        r-> PCLATH_encoded= r-> GP_Reg_encoded[0x0A];

//PC needs to be calculated from PCL and PCLATH.. Decode the values
		
	//	PRINT("\nDecoding PCL_encoded\n");
		r-> PCL = error_detect_correct_decode(r-> PCL_encoded, fnew, cp, r, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr ); //decoded PCL
		r->GP_Reg[2] = r-> PCL;
		r-> GP_Reg[0x82]= r->GP_Reg[2];
	//	PRINT("Decoded PCL: %x\n", r-> PCL);

		//PRINT("\nDecoding PCLATH_encoded\n");
		r->PCLATH = error_detect_correct_decode( r-> PCLATH_encoded, fnew, cp, r, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr ); //decoded PCLATH
		r-> GP_Reg[0x0A] = r->PCLATH;
		r-> GP_Reg[0x8A] = r-> GP_Reg[0x0A];
       // PRINT("Decoded PCLATH: %x\n", r-> PCLATH);

		//PRINT("\nCalculating PC\n");
		r->PC = (r->PCL | (r->PCLATH << 8)) & 0x1FFF; //Limit to 13 bits. Program counter is 13 bits

		//PRINT("Exiting increment_PC()\n");
	
return 0;
}  


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*int increment_PC_double_pointer(struct registers **r)
{

	if ((*r)-> GP_Reg[2] == 0xFF)
	{

		(*r)-> GP_Reg[0x0A]= (error_detect_correct_decode( (*r)-> GP_Reg[0x0A] )) +1 ; //decoded PCL i.e., 0x0A location + 1

		//(*r)-> GP_Reg[0x0A] = (*r)-> GP_Reg[0x0A] + 1; //Increment PCLATH
	}


//PCL= GP_Reg[2] and GP_Reg[0x82]
        (*r)-> GP_Reg[2]= ((*r)-> GP_Reg[2] + 1) & 0xFF; //Limit PCL to 8 bits only
        (*r)-> GP_Reg[0x82]= (*r)-> GP_Reg[2]; //Bank 1 and Bank 0
        (*r)-> PCL= (*r)-> GP_Reg[2];

//PCLATH
        (*r)-> GP_Reg[0x8A]= (*r)-> GP_Reg[0x0A]; //Bank 1 and Bank 0
        (*r)-> PCLATH= (*r)-> GP_Reg[0x0A];

        (*r)-> PC = ((*r)-> PCL | ((*r)-> PCLATH << 8)) & 0x1FFF; //Limit to 13 bits. Program counter is 13 bits


return 0;
}  

*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/* //this is for add program only, not for matrix multiplication
int instruction_decode(struct registers *r1, struct instructions *i1, int program_memory[] ,struct crash_parameters *cp, FILE *fnew, FILE *fp, time_t start_seconds)
{

  int opcode = 0;
  int reg_index=0,  reg_file_addr = 0, d=0;

		i1->decode_bits= (r1->instruction & 0x3000)>> 12;  // bits 13 and 14
        PRINT("Decode bits= %d \n", i1->decode_bits);

             
        i1->instruction= r1->instruction; //Instruction fetched 
        i1->opcode= opcode; 
        i1->reg_file_addr= reg_file_addr;
        i1->d= d;
        i1->reg_index= reg_index;
        i1->bit = 0;
        i1->immediate_value = 0;


        switch (i1->decode_bits)
        {
                case 0:
                        decode_byte_instr(i1,cp,r1,program_memory,fnew,fp, start_seconds);
                        break;

                case 1:
                        decode_bit_instr(r1,i1,cp,fnew,fp, start_seconds, program_memory);  
                        break;

                case 2:
                        call_goto_instr(r1,i1,cp,fnew,fp, start_seconds,program_memory);  
                        break;

                case 3:
                        literal_control_instr(r1, i1,cp,fnew,fp, start_seconds,program_memory);    
                        break;

                default:
                        printf("Invalid decode_bits inside main\n");
						fprintf(fnew,"Invalid decode_bits inside main\n");
                        break;
        }

		PRINT("decode done\n");
       

return 0;
}
*/

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int instruction_decode_matrix_mult(struct registers *r1, struct instructions *i1, int program_memory[], int program_memory_encoded[], struct crash_parameters *cp, FILE *fnew, FILE *fPC, FILE *finstr, time_t start_seconds)
{

  int opcode = 0;
  int reg_index=0,  reg_file_addr = 0, d=0;

		i1->decode_bits= (r1->instruction & 0x3000)>> 12;  // bits 13 and 14
        PRINT("Decode bits= %d \n", i1->decode_bits);
	//	printf("Instruction decode\n");
             
        i1->instruction= r1->instruction; //Instruction fetched . This is the most important assignment in the entire program
        i1->opcode= opcode; 
        i1->reg_file_addr= reg_file_addr;
        i1->d= d;
        i1->reg_index= reg_index;
        i1->bit = 0;
        i1->immediate_value = 0;


        switch (i1->decode_bits)
        {
                case 0:
                        decode_byte_instr(i1,cp,r1,program_memory,program_memory_encoded,fnew, fPC, finstr, start_seconds);
                        break;

                case 1:
                        decode_bit_instr(r1,i1,cp,fnew, fPC, finstr, start_seconds, program_memory,program_memory_encoded);  
                        break;

                case 2:
                        call_goto_instr(r1,i1,cp,fnew, fPC, finstr, start_seconds,program_memory,program_memory_encoded);  
                        break;

                case 3:
                        literal_control_instr(r1, i1,cp,fnew, fPC, finstr, start_seconds,program_memory,program_memory_encoded);    
                        break;

                default:
                        printf("Invalid decode_bits inside main\n");
						fprintf(fnew,"Invalid decode_bits inside main\n");
                        break;
        }



PRINT("decode done\n");
       

return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


int decode_byte_instr(struct instructions *i1, struct crash_parameters *cp, struct registers *r1, int program_memory[],int program_memory_encoded[], FILE *fnew, FILE *fPC, FILE *finstr, time_t start_seconds)

{
        
		int temp_reg_index=0; 
        temp_reg_index = (i1->instruction) & 0x007F;
        i1->d= (i1->instruction & 0x80) >> 7;
//      i1->reg_index = (i1->reg_file_addr) - 12; // Reg file starts only from 0CH = 12
         if (temp_reg_index == 0) //location 0 is INDF register.. used for Indirect addressing. Read content of FSR register and use it as the address or the new reg_index
		{
			i1-> reg_file_addr = r1-> GP_Reg[0x04]; //FSR register is at location 4. Content of FSR is the new reg_index
		}
		else 
		{
			i1-> reg_file_addr = temp_reg_index; //use the decoded reg_index obtained from the instruction as it is.
		}


		i1->reg_index = (i1->reg_file_addr); // Reg file starts only from 0CH = 12
        i1->opcode = (i1->instruction & 0xFF00) >> 8;
		
        PRINT("---------------------------------------------------------------------\n");
        PRINT("INSTRUCTION DECODE >> Byte instructions\n");

        if (i1->instruction==0x0063)
                {
                        i1->instr_mnemonic_enum = SLEEP;
                        PRINT("Instruction mnemonic = SLEEP\n");
                }
        else if (i1->instruction==0x0064)
                {
                        i1->instr_mnemonic_enum = CLRWDT;
                        PRINT("Instruction mnemonic = CLRWDT\n");
                }
        else if (i1->instruction==0x0008)
                {
                        i1->instr_mnemonic_enum = RETURN;
                        PRINT("Instruction mnemonic = RETURN\n");
		//printf("Instruction fetched from program_memory[%x] is %x\n",((r1-> PC)), program_memory[(r1-> PC)]);
		//fprintf(fnew,"Instruction fetched from program_memory[%x] is %x\n",((r1-> PC)), program_memory[(r1-> PC)]);
		
                }
        else if (i1-> instruction==0x0009)
                {
                        i1->instr_mnemonic_enum = RETFIE;
                        PRINT("Instruction mnemonic = RETFIE\n");
                }
        else

        switch (i1-> opcode)
        {
                case 0:
                        if (i1-> d==0)
                                {
                                PRINT("Instruction mnemonic = NOP\n");
                               // fprintf(fnew,"Instruction mnemonic = NOP\n");
                                i1->instr_mnemonic_enum = NOP;
                                }
                        else
                                {
                                PRINT("Instruction mnemonic = MOVWF\n");
                                i1->instr_mnemonic_enum = MOVWF;
                                }
                                
                break;

                case 1:
                                if (i1-> d==0)
                                {
                                PRINT("Instruction mnemonic = CLRW\n");
                                i1->instr_mnemonic_enum = CLRW;
                                }
                        else
                                {
                                PRINT("Instruction mnemonic = CLRF\n");
                                i1->instr_mnemonic_enum = CLRF;
                                }
                break;
                
                case 2:
                        PRINT("Instruction mnemonic = SUBWF\n");
                        i1->instr_mnemonic_enum = SUBWF;                        
                break;

                case 3:
                        PRINT("Instruction mnemonic = DECF\n");
                        i1->instr_mnemonic_enum = DECF;
                break;

                case 4:
                        PRINT("Instruction mnemonic = IORWF\n");

                        i1->instr_mnemonic_enum = IORWF;
                break;

                case 5:
                        PRINT("Instruction mnemonic = ANDWF\n");
                        i1->instr_mnemonic_enum = ANDWF;

                break;
                
                case 6:
                        PRINT("Instruction mnemonic = XORWF\n");
                        i1->instr_mnemonic_enum = XORWF;
                break;

                case 7:
                        PRINT("Instruction mnemonic = ADDWF\n");
                        i1->instr_mnemonic_enum = ADDWF;
                break;

                case 8:
                        PRINT("Instruction mnemonic = MOVF\n");
                        i1->instr_mnemonic_enum = MOVF;
                break;

                case 9:
                        PRINT("Instruction mnemonic = COMF\n");
                        i1->instr_mnemonic_enum = COMF;
                break;
                
                case 10:
                        PRINT("Instruction mnemonic = INCF\n");
                        i1->instr_mnemonic_enum = INCF;
                break;

                case 11:
                        PRINT("Instruction mnemonic = DECFSZ\n");
                        i1->instr_mnemonic_enum = DECFSZ;
                break;

                case 12:
                        PRINT("Instruction mnemonic = RRF\n");
                        i1->instr_mnemonic_enum = RRF;
                break;

                case 13:
                        PRINT("Instruction mnemonic = RLF\n");
                        i1->instr_mnemonic_enum = RLF;
                break;
                
                case 14:
                        PRINT("Instruction mnemonic = SWAPF\n");
                        i1->instr_mnemonic_enum = SWAPF;
                break;

                case 15:
                        PRINT("Instruction mnemonic = INCFSZ\n");
                        i1->instr_mnemonic_enum = INCFSZ;
                break;

                default: printf("\nCRASH: Crash due to illegal opcode\n");
						 fprintf(fnew,"\nCRASH: Crash due to illegal opcode\n");
						 
						 cp->crash_dueto_illegal_opcode++;
						 report_crash_and_reset(r1,  program_memory, program_memory_encoded,cp, start_seconds,i1, fnew, fPC, finstr);
						 reset_instruction_after_crash(i1);
                break;

        }
PRINT("-------------------------------------------------------------------\n");
return 0;

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int decode_bit_instr(struct registers *r1, struct instructions *i1, struct crash_parameters *cp, FILE *fnew, FILE *fPC, FILE *finstr, time_t start_seconds, int program_memory[], int program_memory_encoded[])
{
        int temp_reg_index=0;         
		temp_reg_index =  (i1->instruction) & 0x007F;
        i1-> bit= ((i1->instruction) & 0x0380) >> 7;
		if (temp_reg_index == 0) //location 0 is INDF register.. used for Indirect addressing. Read content of FSR register and use it as the address or the new reg_index
		{
			i1-> reg_file_addr = r1-> GP_Reg[0x04]; //FSR register is at location 4. Content of FSR is the new reg_index
		}
		else 
		{
			i1-> reg_file_addr = temp_reg_index; //use the decoded reg_index obtained from the instruction as it is.
		}

        i1-> reg_index = (i1-> reg_file_addr) ; // Reg file starts only from 0CH = 12
        i1-> opcode = ((i1-> instruction) & 0x1C00) >> 10;
        PRINT("-------------------------------------------------------------------\n");
        PRINT("INSTRUCTION DECODE >> Bit instructions\n");


        switch (i1-> opcode)
        {
                case 4:
                        PRINT("Instruction mnemonic = BCF\n");
                        i1->instr_mnemonic_enum = BCF;
                break;

                case 5:
                        PRINT("Instruction mnemonic = BSF\n");
                        i1->instr_mnemonic_enum = BSF;
                break;
                
                case 6:
                        PRINT("Instruction mnemonic = BTFSC\n");
                        i1->instr_mnemonic_enum = BTFSC;
                break;

                case 7:
                        PRINT("Instruction mnemonic = BTFSS\n");
                        i1->instr_mnemonic_enum = BTFSS;
                break;

                
                default: printf("\nCRASH: Crash due to illegal opcode\n");
					 	 fprintf(fnew,"\nCRASH: Crash due to illegal opcode\n");
						  
						 cp->crash_dueto_illegal_opcode++;
						 
						 report_crash_and_reset(r1,  program_memory,program_memory_encoded, cp, start_seconds,i1, fnew, fPC, finstr);
						 reset_instruction_after_crash(i1);
                break;

        }

PRINT("-------------------------------------------------------------------\n");         
return 0;

}
        
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int literal_control_instr(struct registers *r1, struct instructions *i1, struct crash_parameters *cp, FILE *fnew, FILE *fPC, FILE *finstr, time_t start_seconds, int program_memory[], int program_memory_encoded[])
{
                                                
        i1-> immediate_value = (i1-> instruction) & 0x00FF;
        i1-> opcode = ((i1->instruction) & 0x3F00) >> 8;
PRINT("-------------------------------------------------------------------\n");
PRINT("INSTRUCTION DECODE >> Literal and control instructions\n");
        switch (i1-> opcode)
        {
                case 0x30: 
                case 0x31: 
                case 0x32: 
                case 0x33:
                        PRINT("Instruction mnemonic = MOVLW\n");
                        i1->instr_mnemonic_enum = MOVLW;
                break;

                case 0x34: 
                case 0x35: 
                case 0x36:
        case 0x37:
                        PRINT("Instruction mnemonic = RETLW\n");
                        i1->instr_mnemonic_enum = RETLW;
                break;
                
                case 0x38:
                        PRINT("Instruction mnemonic = IORLW\n");
                        i1->instr_mnemonic_enum = IORLW;
                break;

                case 0x39:
                        PRINT("Instruction mnemonic = ANDLW\n");
                        i1->instr_mnemonic_enum = ANDLW;
                break;

                case 0x3A:
                        PRINT("Instruction mnemonic = XORLW\n");
                        i1->instr_mnemonic_enum = XORLW;
                break;

                case 0x3C: 
                case 0x3D:
                        PRINT("Instruction mnemonic = SUBLW\n");
                        i1->instr_mnemonic_enum = SUBLW;
                break;
                
                case 0x3E: 
                case 0x3F:
                        PRINT("Instruction mnemonic = ADDLW\n");
                        i1->instr_mnemonic_enum = ADDLW;
                break;

                default: printf("\nCRASH: Crash due to illegal opcode\n");
						 fprintf(fnew,"\nCRASH: Crash due to illegal opcode\n");
						 
						 cp->crash_dueto_illegal_opcode++;
						 report_crash_and_reset(r1,  program_memory,program_memory_encoded, cp, start_seconds,i1, fnew, fPC, finstr);
						 reset_instruction_after_crash(i1);
                break;

        }
PRINT("-------------------------------------------------------------------\n");
return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int call_goto_instr(struct registers *r1, struct instructions *i1,struct crash_parameters *cp, FILE *fnew, FILE *fPC, FILE *finstr, time_t start_seconds, int program_memory[], int program_memory_encoded[])
{
                                                
        i1-> immediate_value = (i1-> instruction) & 0x07FF;
        i1-> opcode = ((i1-> instruction) & 0x3800) >> 11;
PRINT("-------------------------------------------------------------------\n");
PRINT("INSTRUCTION DECODE >> CALL/GOTO instructions\n");
        
        switch (i1-> opcode)
        {
                case 4:
                        PRINT("Instruction mnemonic = CALL\n");
                        i1->instr_mnemonic_enum = CALL;
                break;

                case 5:
                        PRINT("Instruction mnemonic = GOTO\n");
                        i1->instr_mnemonic_enum = GOTO;
                break;
                
                default:printf("\nCRASH: Crash due to illegal opcode\n");
						fprintf(fnew,"\nCRASH: Crash due to illegal opcode\n");
  					    
						cp->crash_dueto_illegal_opcode++;
						report_crash_and_reset( r1,  program_memory,program_memory_encoded, cp, start_seconds,i1, fnew, fPC, finstr);
						reset_instruction_after_crash(i1);
                break;

        }
                
PRINT("-------------------------------------------------------------------\n");
return 0;
}




///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int bit_flips(struct registers *r2,  int program_memory[],int program_memory_encoded[],  struct crash_parameters *cp, time_t start_seconds,struct instructions *i1, FILE *fnew, FILE *fPC, FILE *finstr, FILE *fmem, FILE *freg)

{
      	PRINT("bit flip call\n");

		int random_bit=0;
        int i=0, c=0, ii=0;
		int less=0, more=0;
		int temp=0;
     	
		time_t seconds = time(NULL);
		if (seconds == previous_time) 
			return;
		previous_time = seconds;
		//Get value from system clock and place in seconds variable. 
		PRINT("Value of seconds %lu\n", seconds);
		srand ((unsigned int)seconds);

		time_t crash_time;

		//Flip 1 bit in General purpose register
		// generate random number between 0 and PROBABILITY_INVERSE

		cp->random_number = rand() % PROBABILITY_INVERSE; // probability of flipping is (1/ (probability_inverse))
		less=PROBABILITY_INVERSE - RANDOM_GUESS_RANGE;
		more=PROBABILITY_INVERSE - 1;


//Flip bits only under this condition
	if((less< cp->random_number) && (cp->random_number < more)) // probability of generating some number within the range: (1/ (probability_inverse))
	{

		cp->bit_flipped ++ ;       
		 printf("\nFlip function called: Random number generated: %d\n",cp->random_number);
		fprintf(fnew,"\nFlip function called: Random number generated: %d\n",cp->random_number);

		printf("Number of instruction cycles executed : %llu\n",cp->instr_cycles);
            fprintf(fnew,"Number of instruction cycles executed : %llu\n",cp->instr_cycles);

	
		printf("Number of total instruction cycles executed: %llu\n",cp->instr_cycles_for_error);
            fprintf(fnew,"Number of total instruction cycles executed: %llu\n",cp->instr_cycles_for_error);

if(cp->flip_bit_flag==0) //If you enter this if statement without previous bit flips, then set thsi to 1.
			cp->flip_bit_flag=1; //Set flag when bit flips function is called. Check for program errors only when this is set.

		else 
/*This else part will be entered only if the probability is high.
If you enter this, before resetting the flag, that is, still when the check_error function is checking for errors at all instructions, then it means that 
a bit has flipped even before all instructions have been checked for errors. Hence reset the count to zero so that all instructions will be checked again
*/			cp->opcode_count = 0; //Can be used for counting double errors if it happens at the same PC location


	PRINT("Flip flag set to %d\n",cp->flip_bit_flag);
	PRINT("\nBit flip function called\n");
//Set this flag to use in the function:check_illegal_instr and clear it in that function
		cp->flip_bit_flag_for_illegal_inst=1; 


		cp->random_choose = rand() % 2; //choose between 0 and 1
		printf("random choose=%d\n",cp->random_choose);

	if(cp->random_choose == 0)
	{

		cp->random_reg[cp->reg_count] = rand() % 256 ; // Random number between 0 and 255
		
		//cp->random_reg[cp->reg_count] = 2 ; //Testing PC crash

	    random_bit = rand() % 13 ; // Random number between 0 and 12.. 13 bits
	
	printf("Random number in register location: %d \n", cp->random_reg[cp->reg_count]); //Print the random bit flipped in the memory to a file
	fprintf(freg,"%d \n", cp->random_reg[cp->reg_count]); //Print the random bit flipped in the memory to a file
	
	    // printf("Random reg selected:%d, random bit to flip in this reg is %d\n",cp-> random_reg[cp->reg_count],random_bit);
	    PRINT("Content of the encoded random reg location[%d] is (in hex) %x\n",cp-> random_reg[cp->reg_count],r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]);

	
printf("Encoded Content of the reg[%x] before flipping, is (in hex)**** %x\n",cp-> random_reg[cp->reg_count], (r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]));

	fprintf(fnew,"Encoded Content of the reg[%x] before flipping, is (in hex)%x\n",cp-> random_reg[cp->reg_count], (r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]));

	 printf("Content of the reg[%x] before flipping, is (in hex)**** %x\n",cp-> random_reg[cp->reg_count], only_decode(r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]));

	fprintf(fnew,"Content of the reg[%x] before flipping, is (in hex)%x\n",cp-> random_reg[cp->reg_count], only_decode(r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]));

	printf("random_bit=%d\n", random_bit);
	fprintf(fnew,"random_bit=%d\n", random_bit);

	if(random_bit==0|| random_bit==5 || random_bit==9 || random_bit==11 || random_bit==12)
	{
		printf("Parity bit is flipped, not data bit%d\n", random_bit);
		fprintf(fnew,"Parity bit is flipped, not data bit\n", random_bit);
	}

        switch(random_bit)
        {
                case 0:
                r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]=  r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]] ^(1 << 0);
                break;
        
                case 1:
                r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]=  r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]] ^(1 << 1);
                break;

                case 2:
                r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]=  r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]] ^(1 << 2);
                break;

                case 3:
                r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]=  r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]] ^(1 << 3);
                break;

                case 4:
                r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]=  r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]] ^(1 << 4);
                break;

                case 5:
                r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]=  r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]] ^(1 << 5);
                break;

                case 6:
                r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]=  r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]] ^(1 << 6);
                break;

                case 7:
                r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]=  r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]] ^(1 << 7);
                break;

                case 8:
                r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]=  r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]] ^(1 << 8);
                break; 

                case 9:
                r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]=  r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]] ^(1 << 9);
                break;

				case 10:
                r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]=  r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]] ^(1 << 10);
                break;

				case 11:
                r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]=  r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]] ^(1 << 11);
                break;

				case 12:
                r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]=  r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]] ^(1 << 12);
                break;

				default: 
				printf("Invalid bit flip case\n");
				fprintf(fnew,"Invalid bit flip case\n");
                break;
        }
        
        
printf("Encoded Content of the reg[%x] after flipping, is (in hex)**** %x\n",cp-> random_reg[cp->reg_count], (r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]));

	fprintf(fnew,"Encoded Content of the reg[%x] after flipping, is (in hex)%x\n",cp-> random_reg[cp->reg_count], (r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]));
	
	printf("In bit flip(), Bit flipped, Content of the reg[%x] was flipped to %x\n", cp-> random_reg[cp->reg_count], only_decode(r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]));	
	
	fprintf(fnew,"In bit flip(), Bit flipped, Content of the reg[%x] was flipped to %x\n", cp-> random_reg[cp->reg_count], only_decode(r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]));	

//Condition for program crash if Program counter value changes:
		if (cp-> random_reg[cp->reg_count] == 0x02 || cp-> random_reg[cp->reg_count] == 0x82 || cp-> random_reg[cp->reg_count] == 0x0A || cp-> random_reg[cp->reg_count] == 0x8A)

       		 {
			 			
			cp->crash_avoided = cp->crash_avoided + 1; 
			(cp-> crash_dueto_PC) ++;
			
			printf("***********************************************************************\n");
		    fprintf(fnew,"***********************************************************************\n");   
   
			printf("\nCrash Avoided number:%d \n",(cp->crash_avoided));
			fprintf(fnew,"\nCrash Avoided number:%d \n",(cp->crash_avoided));

			printf("Program crash would have been due to PC value at location %x getting affected\n", cp-> random_reg[cp->reg_count]);
			fprintf(fnew,"Program crash would have been due to PC value at location %x getting affected\n", cp-> random_reg[cp->reg_count]);

			printf("Actual PC value (in hex)=%x, instruction opcode that was getting executed (in hex)=%x\n", (r2-> PC), program_memory[ (r2-> PC)]);
			fprintf(fnew,"Actual PC value (in hex)=%x, instruction opcode that was getting executed (in hex)=%x\n", (r2-> PC), program_memory[ (r2-> PC)]);


			printf("Random number that got generated this time was: %d\n", cp->random_number );
			fprintf(fnew,"Random number that got generated this time was: %d\n", cp->random_number );

    
           // PRINT("Content of the reg[%x] is (in hex): %x\n", cp-> random_reg[cp->reg_count], r2->GP_Reg_encoded[cp-> random_reg[cp->reg_count]]);

			crash_time= time(NULL);
			//printf("Number of successful program runs before the crash: %llu\n",cp->program_runs);
			printf("Time of crash number %d is %ld seconds since January 1, 1970\n",cp->crash_avoided, crash_time);
			fprintf(fnew,"Time of crash number %d is %ld seconds since January 1, 1970\n",cp->crash_avoided, crash_time);
			
			printf("At crash %d,time since the beginning of program execution is: %ld (in seconds)\n", cp->crash_avoided, (crash_time-start_seconds));
			fprintf(fnew,"At crash %d,time since the beginning of program execution is: %ld (in seconds)\n", cp->crash_avoided, (crash_time-start_seconds));
			cp->crash_avoided_time_array[cp->crash_avoided] = (crash_time-start_seconds);

			//cp->program_runs= (cp->instr_cycles)/(NUM_OF_INSTR * CLOCKS_PER_INSTR * NUM_OF_PGM_RUNS);
			cp->crash_avoided_at_instr[cp->crash_avoided] = cp->instr_cycles;
			printf("Number of instruction cycles executed before the crash: %llu\n",cp->instr_cycles);
            fprintf(fnew,"Number of instruction cycles executed before the crash: %llu\n",cp->instr_cycles);
	
			         
//-------------------------------------Detect and Correct the error-------------------------------------

		printf("\n***STARTING ERROR CORRECTION ON PC REG LOCATIONS***\n");
		fprintf(fnew,"\n***STARTING ERROR CORRECTION ON PC REG LOCATIONS***\n");

		r2->GP_Reg[0x02]= error_detect_correct_decode( r2->GP_Reg_encoded[0x02], fnew, cp, r2, program_memory, program_memory_encoded, start_seconds, i1, fPC, finstr);
		r2->GP_Reg[0x82]= error_detect_correct_decode( r2->GP_Reg_encoded[0x82], fnew, cp, r2, program_memory, program_memory_encoded, start_seconds, i1, fPC, finstr );
		r2->GP_Reg[0x0A]= error_detect_correct_decode( r2->GP_Reg_encoded[0x0A], fnew, cp, r2, program_memory, program_memory_encoded, start_seconds, i1, fPC, finstr );
		r2->GP_Reg[0x8A]= error_detect_correct_decode( r2->GP_Reg_encoded[0x8A], fnew, cp, r2, program_memory, program_memory_encoded, start_seconds, i1, fPC, finstr );


//encode and write it back
		r2->GP_Reg_encoded[0x02]= hamming_encoding(r2->GP_Reg[0x02]);
		r2->GP_Reg_encoded[0x82]= hamming_encoding(r2->GP_Reg[0x82]);
		r2->GP_Reg_encoded[0x0A]= hamming_encoding(r2->GP_Reg[0x0A]);
		r2->GP_Reg_encoded[0x8A]= hamming_encoding(r2->GP_Reg[0x8A]);


		r2-> PCL = r2->GP_Reg[2];
		r2->PCLATH = r2-> GP_Reg[0x0A];
		
		//Calculating PC
		r2->PC = (r2->PCL | (r2->PCLATH << 8)) & 0x1FFF; //Limit to 13 bits. Program counter is 13 bits


	printf("\nERROR CORRECTION: Corrected PC values (location 2 and 82 are PCL, location A and 8A are PCLATH) are:\n");
	fprintf(fnew,"\nERROR CORRECTION: Corrected PC values (location 2 and 82 are PCL, location A and 8A are PCLATH) are:\n");

    printf("GP_Reg[0x02] = %x, GP_Reg[0x82] = %x, GP_Reg[0x0A] = %x, GP_Reg[0x8A] = %x\n\n", r2->GP_Reg[0x02], r2->GP_Reg[0x82], r2->GP_Reg[0x0A], r2->GP_Reg[0x8A]);
    fprintf(fnew,"GP_Reg[0x02] = %x, GP_Reg[0x82] = %x, GP_Reg[0x0A] = %x, GP_Reg[0x8A] = %x\n\n", r2->GP_Reg[0x02], r2->GP_Reg[0x82], r2->GP_Reg[0x0A], r2->GP_Reg[0x8A]);

  printf("***********************************************************************\n");
  fprintf(fnew,"***********************************************************************\n");   

//------------------------Reset conditions after crash---------------------------------------

			//reset_after_crash(r2, program_memory,program_memory_encoded, cp, start_seconds, fnew, fPC, finstr);
//-------------------------------------------------------------------------------
   		  }

	}//end if(cp->random_choose == 0)

	else if (cp->random_choose == 1)
	{

		//Flip 1 bit in program memory - will change the opcode
		// generate random number: 
         cp->random_mem[cp->mem_count] = rand() % 8193; // Random number between 0 and 8192. Store it in an array to keep track and compare later

	printf("Random number in memory location: %d \n", cp->random_mem[cp->mem_count]); //Print the random bit flipped in the memory to a file
			
	fprintf(fmem,"%d \n", cp->random_mem[cp->mem_count]); //Print the random bit flipped in the memory to a file

	//mem_count just keeps count of how many memory locations have been flipped. And is the array index for the array whoch stores the flipped location address

                cp->random_bit_mem = rand() % 19 ; // Random number between 0 and 18. .19 bits in total
		
  printf("\nrandom_bit_mem=%d\n", cp->random_bit_mem);
	fprintf(fnew,"\nrandom_bit_mem=%d\n", cp->random_bit_mem);

printf("Encoded Content of the program mem[%x] before bitflip is (in hex): %x\n",cp-> random_mem[cp->mem_count], program_memory[cp-> random_mem[cp->mem_count]]);
fprintf(fnew,"Encoded Content of the program mem[%x] before bitflip is (in hex): %x\n",cp-> random_mem[cp->mem_count], program_memory[cp-> random_mem[cp->mem_count]]);

printf("Content of the mem[%x] before flipping, is (in hex)**** %x\n",cp->random_mem[cp->mem_count], only_decode(program_memory_encoded[cp->random_mem[cp->mem_count]]));

fprintf(fnew,"Content of the mem[%x] before flipping, is (in hex)**** %x\n",cp->random_mem[cp->mem_count], only_decode(program_memory_encoded[cp-> random_mem[cp->mem_count]]));

        //Bit 0 is the LSB (rightmost) and Bit 18 is MSB (leftmost)
            switch(cp->random_bit_mem)
            {
                    case 0:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 0);
                    break;
            
                    case 1:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 1);
                    break;

                    case 2:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 2);
                    break;

                    case 3:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 3);
                    break;

                    case 4:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 4);
                    break;

                    case 5:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 5);
                    break;

                    case 6:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 6);
                    break;

                    case 7:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 7);
                    break;

                    case 8:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 8);
                    break;

					case 9:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 9);
                    break;

					case 10:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 10);
                    break;

					case 11:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 11);
                    break;

					case 12:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 12);
                    break;

					case 13:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 13);
                    break;

					case 14:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 14);
                    break;
				
					case 15:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 15);
                    break;

					case 16:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 16);
                    break;

					case 17:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 17);
                    break;

					case 18:
                    program_memory_encoded[cp-> random_mem[cp->mem_count]]=    program_memory_encoded[cp-> random_mem[cp->mem_count]] ^(1 << 18);
                    break;

					default: printf("Invalid bit flip case\n");
                    fprintf(fnew,"Invalid bit flip case\n");
					break;
            }
    
       
printf("Encoded Content of the mem[%x] after flipping, is (in hex)**** %x\n",cp-> random_mem[cp->mem_count], program_memory_encoded[cp-> random_mem[cp->mem_count]]);

fprintf(fnew,"Encoded Content of the mem[%x] after flipping, is (in hex)**** %x\n",cp-> random_mem[cp->mem_count], program_memory_encoded[cp-> random_mem[cp->mem_count]]);

	printf("In bit flip(), Bit flipped, Content of the mem[%x] was flipped to %x\n", cp-> random_mem[cp->mem_count],only_decode(program_memory_encoded[cp-> random_mem[cp->mem_count]]));	
	
	fprintf(fnew,"In bit flip(), Bit flipped, Content of the mem[%x] was flipped to %x\n", cp-> random_mem[cp->mem_count],only_decode(program_memory_encoded[cp-> random_mem[cp->mem_count]]));	

	} //end if (cp->random_choose == 1)

	cp->reg_count = cp->reg_count + 1;
	cp->mem_count = cp->mem_count + 1;

 }  // End the "If probability is met"
PRINT("Ending bitflips function\n");

return 0;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Check for program error (error in data)


int check_pgm_error(struct crash_parameters *cp, struct registers *r2, struct instructions *i1, int program_memory[], int program_memory_encoded[], FILE *fnew, FILE *fPC, FILE *finstr, time_t start_seconds)
{
//Check if the data being accessed by the instruction has been flipped.. hence leading to incorrect data
	int i=0,j=0;

    //Data at the reg_index (which was decoded in decode step) has changed.. and hence leads to an error in computed data
	if (cp->flip_bit_flag==1 ) //This flag is set only when the bit is flipped.
	//&& cp->opcode_count++ < r2->max_instr) 
//And repeat this comparison for every opcode in the program, since the flipped reg can be equal to the reg file in any of the instructions..
//Hopefully another bit doesnt flip during this comparison
	{ 
		cp->flip_bit_flag=0; //Reset flag moved here.. no need to compare with all instructions, since correcting error the very first time..
		

		PRINT("Reg file address= %x\n",i1-> reg_index);
		for(i=0;i < cp-> reg_count;i++) //Check if the reg index is equal to any of the previously flipped registers
/*Reg count has been incremented at the end of the bit flips function. And this check program error has been called after the bitflips function.
Hence, the for loop should run only till less than reg_count and not equal to reg_count */
		{
			if (i1->reg_index == cp->random_reg[i]) 
				{
				cp-> reg_index_match = 1;
				printf("\n*****Reg file address: %x, matches with random reg:%x. Register bit flip array index=%d*****\n",i1-> reg_index,cp-> random_reg[i], i);
				printf("\nChecking program error, Content of the random reg[%x] is (in hex) %x\n", cp-> random_reg[i], only_decode(r2->GP_Reg_encoded[cp-> random_reg[i]]));

			fprintf(fnew,"\nChecking program error, Content of the random reg[%x] is (in hex) %x\n", cp-> random_reg[i], only_decode(r2->GP_Reg_encoded[cp-> random_reg[i]]));
				}
		}
	
		if (cp-> reg_index_match == 1)
		// This can be equal even if the same instruction is repeated after a certain number of cycles, hence check for PC value
		{
			cp->incorrect_data++; //even if error happens at same PC, count the error..
			printf("POSSIBLE ERROR: Incorrect data fetched when accessing reg[%x]..Need to check if parity/data was in error.\n",i1->reg_index);
			fprintf(fnew,"POSSIBLE ERROR: Incorrect data fetched when accessing reg[%x]..Need to check if parity/data was in error.\n",i1->reg_index);
			
			printf("PC value= %x, opcode= %x\n",(r2-> PC), program_memory[r2-> PC]);
			fprintf(fnew,"PC value= %x, opcode= %x\n",(r2-> PC), program_memory[r2-> PC]);
	
			//printf("Same PC =%d\n",cp->same_PC);
			//printf("cp-> store_PC_same[0]=%x\n",cp-> store_PC_same[0]);

			cp-> reg_index_match = 0; //reset

			//*************************ERROR CORRECTION****************************************
			printf("Before error correction,encoded content of the reg location %x was: %x\n",i1->reg_index, (r2->GP_Reg_encoded[i1->reg_index]));
			fprintf(fnew,"Before error correction,encoded content of the reg location %x was: %x\n",i1->reg_index,(r2->GP_Reg_encoded[i1->reg_index]));

printf("Before error correction, content of the reg location %x was: %x\n",i1->reg_index, only_decode(r2->GP_Reg_encoded[i1->reg_index]));
			fprintf(fnew,"Before error correction, content of the reg location %x was: %x\n",i1->reg_index, only_decode(r2->GP_Reg_encoded[i1->reg_index]));

			//Error correction
			r2->GP_Reg[i1->reg_index]= error_detect_correct_decode(r2->GP_Reg_encoded[i1->reg_index], fnew, cp, r2, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr); //correct error and decode

			//encode and write it back
			r2->GP_Reg_encoded[i1->reg_index] = hamming_encoding(r2->GP_Reg[i1->reg_index]); 

			printf("After error correction, content of the reg location %x was: %x\n", i1->reg_index, r2->GP_Reg[i1->reg_index]);
			fprintf(fnew,"After error correction, content of the reg location %x was: %x\n",i1->reg_index, r2->GP_Reg[i1->reg_index]);

				printf("After error correction, encoded content of the reg location %x was: %x\n", i1->reg_index, r2->GP_Reg_encoded[i1->reg_index]);
			fprintf(fnew,"After error correction, encoded content of the reg location %x was: %x\n",i1->reg_index, r2->GP_Reg_encoded[i1->reg_index]);

		//fclose(fnew);
			//exit(0);
			//*************************************************************************************

			for(j=0;j < cp->same_PC; j++) //print only first time the error occurs.. hence check for additional constraints
			{
				//printf("cp-> store_PC_same[%d]=%x\n", j, cp-> store_PC_same[j]);
				//if(r2->GP_Reg_encoded[cp-> random_reg[i]] != cp->store_same_reg_modification[j]) // The reg content shouldnt be the same
				if( ((r2-> PC)) != cp-> store_PC_same[j] ) // error for the same instruction should be recorded only once
					{
					cp->set_no_same_PC = 1; //For loop is not entered for the very first time..hence initialised to 1 in main()
					printf("j=%d, PC not same as previous ones..counting as error\n",j);
					//printf("same_PC count=%d, j=%d, cp-> store_PC_same[%d]=%x\n",cp->same_PC, j,j, cp-> store_PC_same[j]);
					}

				else 
					{
					
					cp->set_no_same_PC = 0; // If same PC value
					printf("j=%d,PC %x same as previous ones.. and same reg index. Counting, but not printing to file \n",j,(r2-> PC));
					//fprintf(fnew,"j=%d,PC %x same as previous ones.. and same reg index. Counting, but not printing to file \n",j,(r2-> PC));
					//printf("\nERROR: Incorrect data was being fetched from memory\n");
					//fprintf(fnew,"\nERROR: Incorrect data being fetched from memory\n");
	
					
					printf("Number of instruction cycles executed before the error: %llu\n",cp->instr_cycles_for_error);
					}

			if(cp->set_no_same_PC ==0)
				{
				//report_error() is not called, but the error is counted in incorrect_data++
				break; //The moment the PC matches with any one of the values stored already, exit the for loop
				}
			}
	

			if(cp->set_no_same_PC == 1)
			{ //Prevent the same error from printing and storing multiple times..
				cp->set_no_same_PC =0; //reset
				//*****report error because of incorrect data in the location that is being accessed********************
				//cp->incorrect_data++;
				cp->incorrect_data_flag=1;
								
				cp-> store_PC_same[cp->same_PC]= (r2-> PC); //PC 
				
		  	
				cp->same_PC= (cp->same_PC) +1; //gets incremented only if unique PC value is stored

			
				printf("\nUnique error corrected: Incorrect data was being fetched from memory\n");
				fprintf(fnew,"\nUnique error corrected: Incorrect data was being fetched from memory\n");

				report_error(cp,r2,i1,program_memory,fnew);//Print error only if error occurs at a unique PC value.

			}
		
		} //end if (cp-> reg_index_match == 1)

	} //end if (cp->flip_bit_flag==1)

	/* //this was used when running through all instructions in the program to count errors.
		//now that we are correcting error in the very first error instance, we dont need this
	else
	if (cp->opcode_count == r2->max_instr)
	{
		cp->flip_bit_flag=0; //Reset flag.
		printf("Done comparing the register with flipped bit with all instructions in the program\n\n");
	//fclose(fnew);
	//exit(0);
	}
		*/
return 0;

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Condition for program crash if illegal instruction. This is only if the program_memory contents are flipped
int check_illegal_instr(struct registers *r2,  
                        int program_memory[], 
						int program_memory_encoded[], 
                        struct crash_parameters *cp, 
						time_t start_seconds,
						struct instructions *i1,
						FILE *fnew, 		
						FILE *fPC, 
						FILE *finstr)

{

int ii=0;
int  crash_decode_bits=0;

/*Algorithm:
if the random_mem is in the range of the PC values that the program uses, then there is a possibility that one of the opcode has changed.
Then map the random_mem to the PC value and get the instruction.
Decode the instruction and see which part of the instruction has changed
If 
	- the reg file index has changed 
		-and is one of the illegal mem locations- then it is a crash.
		-and is not an illegal mem location, but some other location, then it will lead to an error in the result

If
	-the opcode has changed, then it will result in error
	-will lead to crash if it is an illegal opcode

If
	-the immediate value has changed, then it will lead to error

If
	-the d bit or b bit has changed ,it will lead to error 

*/
	
//printf("\nCheck illegal instruction... \n"); //Gets printed every cycle

/*If the random_mem (that is the mem location flipped) in the program_memory is in the range of the PC values of the program..
For eg., if random_mem is 2, then program_memory[2] is flipped.
 Check if program_memory[2] contains any instruction. So, check if 2 is one of the PC values. If yes, then one of the valid instructions has changed.
So, now check for different error/crash conditions
*/
if (cp->flip_bit_flag_for_illegal_inst==1) //Check only if a bit has flipped
{
	cp->flip_bit_flag_for_illegal_inst=0; //reset it

	PRINT("cp->random_mem inside check_illegal: %x, cp->random_bit_mem=%x \n", cp->random_mem[(cp->mem_count)-1], cp->random_bit_mem );
//	fprintf(fnew,"cp->random_mem inside check_illegal: %x, cp->random_bit_mem=%x \n", cp->random_mem[(cp->mem_count)-1],cp->random_bit_mem );

	if( ((r2->starting_PC_value) < (cp-> random_mem[(cp->mem_count)-1])) && 
         ((cp-> random_mem[(cp->mem_count)-1]) < r2->Last_valid_PC) )           
	{

	PRINT("Checking if the random number generated is within the range of valid PC values in the program\n");
//	fprintf(fnew,"Checking if the random number generated is within the range of valid PC values in the program\n");
/*Mem count has been incremented at the end of the bit flips function. And this check program error has been called after the bitflips function.
Hence, the condition should check for the mem_count -1 */

//Now check if the decode_bits itself has changed.. else decode the instruction and see which part of the instruction has changed.
        
		if ( (cp->random_bit_mem !=12) || (cp->random_bit_mem !=13) ) //Decode_bits hasnt changed. So, the category of instructions remains same as in the decode function
		{
			//Fetch instruction from the location which has its instruction flipped. PC = (cp-> random_mem[(cp->mem_count)-1])	
			cp->erroneous_instruction = only_decode_14bit_hamming(program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]]);

			printf("PC value (in hex)=%x, erroneous instruction was (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], cp->erroneous_instruction );
			fprintf(fnew,"PC value (in hex)=%x, erroneous instruction was (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], cp->erroneous_instruction);


			crash_decode_bits= (cp->erroneous_instruction & 0x3000)>> 12;  // bits 13 and 14
	        PRINT("Decode bits while verifying program crash= %d \n", crash_decode_bits);

		
	 		switch (crash_decode_bits)
		    {
		        case 0: //handle_byte_instruction_error()
		                //Byte instruction
						handle_byte_instruction_error(r2,program_memory, program_memory_encoded,  cp,start_seconds,i1,fnew,fPC, finstr);
						
		        break;

		        case 1: //handle_bit_instruction_error()
		                //Bit instruction
						handle_bit_instruction_error(r2,program_memory, program_memory_encoded, cp,start_seconds,i1,fnew,fPC, finstr);
				 
		        break;

		        case 2: // Error in CALL GOTO instruction
						
						
						printf("\nCRASH AVOIDED: Control flow instruction has got modified (resulted in CALL/GOTO)\n");
						fprintf(fnew,"\nCRASH AVOIDED:Control flow instruction has got modified (resulted in CALL/GOTO)\n");
				  		
						cp->control_flow_change++;
	 //***********************************correct the incorrect instruction**********************************************************
			//correct the value and opcode
			program_memory[cp-> random_mem[(cp->mem_count)-1]] = error_detect_correct_decode_14bit(program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]], fnew, cp, r2, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr); 
//encode and write it back                                        
program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]]= hamming_encoding_14bit(program_memory[cp-> random_mem[(cp->mem_count)-1]]);

	i1-> immediate_value = (i1-> instruction) & 0x07FF;
	i1-> opcode = ((i1-> instruction) & 0x3800) >> 11;
printf("PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]] );
			fprintf(fnew,"PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]]);

			//*********************************************************************************************************************

				report_crash_avoided( r2,  program_memory,program_memory_encoded, cp, start_seconds,i1, fnew, fPC, finstr);

		        break;

		        case 3: //handle_literal_instruction_error()
		                //Literal and control instruction
						handle_literal_instruction_error(r2,program_memory, program_memory_encoded, cp,start_seconds,i1,fnew,fPC, finstr);
		        break;

		        default:
		                printf("Invalid decode_bits inside crash testing function\n");
						fprintf(fnew,"Invalid decode_bits inside crash testing function\n");
		        break;
		    } //switch close

		} //if random_bit close
		//handle_decode_bit_error()		
		else //If the decode_bits itself has flipped, report- Unable to decode instruction - report program crash
			 // Code for report crash
		{
			 printf("\nCRASH: Decode bits have changed.. cannot correct\n");
			 fprintf(fnew,"\nCRASH: Decode bits have changed.. cannot correct\n");
			 
			 cp->crash_dueto_illegal_opcode++;
			 report_crash_and_reset( r2,  program_memory,program_memory_encoded, cp, start_seconds,i1, fnew, fPC, finstr);
			 reset_instruction_after_crash(i1);
			
		}
	} //close if PC range

} //close if cp->flip_bit_flag_for_illegal_inst
return 0;

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	
int handle_byte_instruction_error(struct registers *r2,  
                        int program_memory[], 
                       	int program_memory_encoded[],
						struct crash_parameters *cp, 
						time_t start_seconds,
						struct instructions *i1,
						FILE *fnew, 		
						FILE *fPC, FILE *finstr)
{



if ( (0 < cp->random_bit_mem) && (cp->random_bit_mem <= 6) ) //If one of the bits 0 to 7 are flipped, it means that the reg index has changed
	{
		cp->crash_reg_index = (cp->erroneous_instruction) & 0x007F; //Extract reg_index

		//Reg index is in error

		if ( ( 0x4F < cp->crash_reg_index && cp->crash_reg_index < 0x7F ) ||
			 ( 0xCF < cp->crash_reg_index && cp->crash_reg_index < 0xFF ) ) 

		{
			(cp-> crash_dueto_illegal_mem)++;
		
			
			printf("\nCRASH AVOIDED: Program crash due to illegal memory access: Trying to access location %x\n", cp->crash_reg_index);
	   		fprintf(fnew,"\nCRASH AVOIDED: Program crash due to illegal memory access: Trying to access location %x\n", cp->crash_reg_index);
		 //***********************************correct the incorrect instruction**********************************************************
			//correct the incorrect reg index
			program_memory[cp-> random_mem[(cp->mem_count)-1]] = error_detect_correct_decode_14bit(program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]], fnew, cp, r2, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr); 
//encode and write it back                                        
program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]]= hamming_encoding_14bit(program_memory[cp-> random_mem[(cp->mem_count)-1]]);

			i1->instruction= program_memory[cp-> random_mem[(cp->mem_count)-1]]; //Instruction fetched . This is the most important assignment in the entire program
			i1-> reg_file_addr = (i1->instruction) & 0x007F;
			i1-> reg_index=i1-> reg_file_addr;

			printf("PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]] );
			fprintf(fnew,"PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]]);

			//*********************************************************************************************************************
			// printf("Content of the program_memory[%x] is (in hex): %x\n", cp->crash_reg_index, program_memory[cp->crash_reg_index]);
			report_crash_avoided( r2,  program_memory, program_memory_encoded, cp, start_seconds,i1, fnew, fPC, finstr);
			
		}


		else 
//If it has not got converted into one of the illegal memory locations, it has nevertheless got converted into some unintended reg file location.
//report error
		{
//Reg index is in error
		cp->incorrect_data_in_instr++;
		
		printf("\nERROR AVOIDED: Byte instruction: Reg file address from which data needs to be fetched, had changed, would've lead to an error in program\n");
		fprintf(fnew,"\nERROR AVOIDED: Byte instruction: Reg file address from which data needs to be fetched, had changed, would've lead to an error in program\n");

		//***********************************correct the incorrect instruction**********************************************************
		//correct the incorrect reg index
		program_memory[cp-> random_mem[(cp->mem_count)-1]] = error_detect_correct_decode_14bit(program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]], fnew, cp, r2, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr); 

//encode and write it back                                        
program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]]= hamming_encoding_14bit(program_memory[cp-> random_mem[(cp->mem_count)-1]]);

		i1->instruction= program_memory[cp-> random_mem[(cp->mem_count)-1]]; //Instruction fetched . This is the most important assignment in the entire program
		i1-> reg_file_addr = (i1->instruction) & 0x007F;
		i1-> reg_index=i1-> reg_file_addr;

	printf("PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]] );
		fprintf(fnew,"PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]]);

		//*********************************************************************************************************************

		report_error(cp,r2,i1,program_memory,fnew);
		
		}

	}
	else 
		if ( (8 <= cp->random_bit_mem) && (cp->random_bit_mem <= 11) )
		//opcode has changed within the same group of instructions.. report error

		{
			cp-> opcode_change++;
			
			printf("\nERROR AVOIDED: Byte instruction: Opcode has changed, will lead to an error in program\n");
			fprintf(fnew,"\nERROR AVOIDED: Byte instruction: Opcode has changed, will lead to an error in program\n");
			
		//***********************************correct the incorrect instruction**********************************************************
		//correct the incorrect opcode
		program_memory[cp-> random_mem[(cp->mem_count)-1]] = error_detect_correct_decode_14bit(program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]], fnew, cp, r2, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr); //correct the incorrect instruction

//encode and write it back                                        
program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]]= hamming_encoding_14bit(program_memory[cp-> random_mem[(cp->mem_count)-1]]);

		i1->instruction= program_memory[cp-> random_mem[(cp->mem_count)-1]]; //Instruction fetched . This is the most important assignment in the entire program
		i1->opcode = (i1->instruction & 0xFF00) >> 8;

	printf("PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]] );
	fprintf(fnew,"PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]]);

		//*********************************************************************************************************************
			report_error(cp,r2,i1,program_memory,fnew);
		
		}

		else if (cp->random_bit_mem == 7) //Destination has changed. report error

		{
			cp->incorrect_data_in_instr++;
			
			printf("\nERROR AVOIDED: Byte instruction: Destination register has changed, will lead to an error in program\n");
			fprintf(fnew,"\nERROR AVOIDED: Byte instruction: Destination register has changed, will lead to an error in program\n");
			
		//***********************************correct the incorrect instruction**********************************************************
		//correct the destination bit
		program_memory[cp-> random_mem[(cp->mem_count)-1]] = error_detect_correct_decode_14bit(program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]], fnew, cp, r2, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr); 

//encode and write it back                                        
program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]]= hamming_encoding_14bit(program_memory[cp-> random_mem[(cp->mem_count)-1]]);

		i1->instruction= program_memory[cp-> random_mem[(cp->mem_count)-1]]; //Instruction fetched . This is the most important assignment in the entire program
		i1->d= (i1->instruction & 0x80) >> 7;

			printf("PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]] );
			fprintf(fnew,"PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]]);

		//*********************************************************************************************************************

			report_error(cp,r2,i1,program_memory,fnew);
		}

return 0;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int handle_bit_instruction_error(struct registers *r2,  
                        int program_memory[], 
                        int program_memory_encoded[], struct crash_parameters *cp, 
						time_t start_seconds,
						struct instructions *i1,
						FILE *fnew, 		
						FILE *fPC, FILE *finstr)
{


if ( (0 < cp->random_bit_mem) && (cp->random_bit_mem <= 6) ) //If one of the bits 0 to 7 are flipped, it means that the reg index has changed
			{
				cp->crash_reg_index = (cp->erroneous_instruction) & 0x007F; //Extract reg_index

				if ( ( 0x4F < cp->crash_reg_index && cp->crash_reg_index < 0x7F ) ||
					 ( 0xCF < cp->crash_reg_index && cp->crash_reg_index < 0xFF ) ) 

				{
					(cp-> crash_dueto_illegal_mem)++;
					printf("\nCRASH AVOIDED: Program crash due to illegal memory access: Trying to access location %x\n", cp->crash_reg_index);
			   		fprintf(fnew,"\nCRASH AVOIDED: Program crash due to illegal memory access: Trying to access location %x\n", cp->crash_reg_index);
					// printf("Content of the program_memory[%x] is (in hex): %x\n", cp->crash_reg_index, program_memory[cp->crash_reg_index]);
					
//***********************************correct the incorrect instruction**********************************************************
		//correct the reg index
		program_memory[cp-> random_mem[(cp->mem_count)-1]] = error_detect_correct_decode_14bit(program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]], fnew, cp, r2, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr); 

//encode and write it back                                        
program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]]= hamming_encoding_14bit(program_memory[cp-> random_mem[(cp->mem_count)-1]]);

		i1->instruction= program_memory[cp-> random_mem[(cp->mem_count)-1]]; //Instruction fetched . This is the most important assignment in the entire program

		i1-> reg_file_addr = (i1->instruction) & 0x007F;
        i1-> reg_index = (i1-> reg_file_addr) ; // Reg file starts only from 0CH = 12
  printf("PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]] );
	fprintf(fnew,"PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]]);

//*********************************************************************************************************************
				report_crash_avoided(r2,  program_memory,program_memory_encoded, cp, start_seconds,i1, fnew, fPC, finstr);

				}

			}
		else 
			if ( (7 <= cp->random_bit_mem) && (cp->random_bit_mem <= 9) )
			//Bit b has changed within the same group of instructions.. report error
			// Code for report error
			{
				cp->incorrect_data_in_instr++;
				
				printf("\nERROR AVOIDED: Bit instruction: Bit value in instruction has changed, will lead to an error in program\n");
				fprintf(fnew,"\nERROR AVOIDED: Bit instruction: Bit value in instruction has changed, will lead to an error in program\n");
//***********************************correct the incorrect instruction**********************************************************
		//correct the bit
				program_memory[cp-> random_mem[(cp->mem_count)-1]] = error_detect_correct_decode_14bit(program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]], fnew, cp, r2, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr); 

//encode and write it back                                        
program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]]= hamming_encoding_14bit(program_memory[cp-> random_mem[(cp->mem_count)-1]]);

				i1->instruction= program_memory[cp-> random_mem[(cp->mem_count)-1]]; //Instruction fetched . This is the most important assignment in the entire program

				i1-> bit= ((i1->instruction) & 0x0380) >> 7;

				printf("PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]] );
	fprintf(fnew,"PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]]);

//*********************************************************************************************************************
		report_error(cp,r2,i1,program_memory,fnew);

			}
			else if ( (cp->random_bit_mem == 10) && (cp->random_bit_mem == 11) ) //
			//opcode has changed within the same group of instructions.. report error
			// Code for report error
			{
				cp->opcode_change++;

				printf("\nERROR AVOIDED: Bit instruction: Opcode has changed, will lead to an error in program\n");
				fprintf(fnew,"\nERROR AVOIDED: Bit instruction: Opcode has changed, will lead to an error in program\n");

                //***********************************correct the incorrect instruction**********************************************************
		//correct the opcode
				program_memory[cp-> random_mem[(cp->mem_count)-1]] = error_detect_correct_decode_14bit(program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]], fnew, cp, r2, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr); 

//encode and write it back                                        
program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]]= hamming_encoding_14bit(program_memory[cp-> random_mem[(cp->mem_count)-1]]);

				i1->instruction= program_memory[cp-> random_mem[(cp->mem_count)-1]]; //Instruction fetched . This is the most important assignment in the entire program	
				i1-> opcode = ((i1-> instruction) & 0x1C00) >> 10;
	printf("PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]] );
	fprintf(fnew,"PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]]);

//*********************************************************************************************************************

				report_error(cp,r2,i1,program_memory,fnew);

			}

return 0;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int handle_literal_instruction_error(struct registers *r2,  
                        int program_memory[], 
                        int program_memory_encoded[],struct crash_parameters *cp, 
						time_t start_seconds,
						struct instructions *i1,
						FILE *fnew, 		
						FILE *fPC, FILE *finstr)
{


if ( (0 < cp->random_bit_mem) && (cp->random_bit_mem <= 7) ) //If one of the bits 0 to 7 are flipped, it means that the immediate value has changed
		{
			cp->incorrect_data_in_instr++;

			printf("\nERROR AVOIDED: Literal and control instruction: immediate value has changed, will lead to an error in program\n");
			fprintf(fnew,"\nERROR AVOIDED: Literal and control instruction: Immediate value has changed, will lead to an error in program\n");	
			//Immediate value is in error
			//***********************************correct the incorrect instruction**********************************************************
		//correct the Immediate value
				program_memory[cp-> random_mem[(cp->mem_count)-1]] = error_detect_correct_decode_14bit(program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]], fnew, cp, r2, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr); 

//encode and write it back                                        
program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]]= hamming_encoding_14bit(program_memory[cp-> random_mem[(cp->mem_count)-1]]);

				i1->instruction= program_memory[cp-> random_mem[(cp->mem_count)-1]]; //Instruction fetched . This is the most important assignment in the entire program
 				i1-> immediate_value = (i1-> instruction) & 0x00FF;
       
	printf("PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]] );
		fprintf(fnew,"PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]]);

//*********************************************************************************************************************
				report_error(cp,r2,i1,program_memory,fnew);

		   		}
				else //whatever else has changed
				//opcode has changed within the same group of instructions.. report error
				{
				cp->opcode_change++;

				printf("\nERROR AVOIDED: Literal and control instruction: Opcode has changed, will lead to an error in program\n");
				fprintf(fnew,"\nERROR AVOIDED: Literal and control instruction: Opcode has changed, will lead to an error in program\n");	
				//Opcode is in error
			//***********************************correct the incorrect instruction**********************************************************
		//correct the Immediate value
				program_memory[cp-> random_mem[(cp->mem_count)-1]] = error_detect_correct_decode_14bit(program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]], fnew, cp, r2, program_memory,program_memory_encoded,start_seconds, i1, fPC, finstr); 

//encode and write it back                                        
program_memory_encoded[cp-> random_mem[(cp->mem_count)-1]]= hamming_encoding_14bit(program_memory[cp-> random_mem[(cp->mem_count)-1]]);

				i1->instruction= program_memory[cp-> random_mem[(cp->mem_count)-1]]; //Instruction fetched . This is the most important assignment in the entire program
				 i1-> opcode = ((i1->instruction) & 0x3F00) >> 8;
printf("PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]] );
	fprintf(fnew,"PC value (in hex)=%x, erroneous instruction corrected (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], program_memory[cp-> random_mem[(cp->mem_count)-1]]);

//*********************************************************************************************************************
				report_error(cp,r2,i1,program_memory,fnew);
			
				}

return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int report_crash_avoided(struct registers *r2,  int program_memory[],int  program_memory_encoded[], struct crash_parameters *cp, time_t start_seconds,struct instructions *i1, FILE *fnew, FILE *fPC, FILE *finstr)
{
	
		int ii=0;

		time_t crash_time;
		
    	cp->crash_avoided= (cp->crash_avoided)+1;
		
		printf("\nCrash Avoided number:%d\n",(cp->crash_avoided));
		fprintf(fnew,"\nCrash Avoided number:%d\n",(cp->crash_avoided));
		
    
    	 crash_time= time(NULL);  

		//cp->program_runs= (cp->instr_cycles)/(NUM_OF_INSTR * CLOCKS_PER_INSTR * NUM_OF_PGM_RUNS);
		cp->crash_avoided_at_instr[cp->crash_avoided] = cp->instr_cycles;  //Save the cycles in an array to finally print it out

		printf("Random number that got generated this time was: %d\n", cp->random_number );
		fprintf(fnew,"Random number that got generated this time was: %d\n", cp->random_number );

		printf("Number of instruction cycles executed before the crash: %llu\n",cp->instr_cycles);
		fprintf(fnew,"Number of instruction cycles executed before the crash: %llu\n",cp->instr_cycles);
	
		//printf("Number of successful program runs before the crash: %llu\n",cp->program_runs);
		printf("Time of crash number %d is %ld seconds since January 1, 1970\n",cp->crash_avoided, crash_time);
	    fprintf(fnew,"Time of crash number %d is %ld seconds since January 1, 1970\n",cp->crash_avoided, crash_time);

		printf("At crash %d,time since the beginning of program execution is: %ld (in seconds)\n", cp->crash_avoided,(crash_time-start_seconds));
		fprintf(fnew,"At crash %d,time since the beginning of program execution is: %ld (in seconds)\n", cp->crash_avoided,(crash_time-start_seconds));
	cp->crash_avoided_time_array[cp->crash_avoided] = (crash_time-start_seconds);

		//**********************Reset conditions after mem crash*******************************
		//reset_after_crash(r2,  program_memory, program_memory_encoded,  cp, start_seconds, fnew, fPC, finstr);


return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int report_crash_and_reset(struct registers *r2,  int program_memory[],int  program_memory_encoded[], struct crash_parameters *cp, time_t start_seconds,struct instructions *i1, FILE *fnew, FILE *fPC, FILE *finstr)
{
	
		int ii=0;

		time_t crash_time;
		
    	cp->crash= (cp->crash)+1;
		
		printf("\nCrash number:%d\n",(cp->crash));
		fprintf(fnew,"\nCrash number:%d\n",(cp->crash));
		
    
    	 crash_time= time(NULL);  

		//cp->program_runs= (cp->instr_cycles)/(NUM_OF_INSTR * CLOCKS_PER_INSTR * NUM_OF_PGM_RUNS);
		cp->crash_at_instr[cp->crash] = cp->instr_cycles;  //Save the cycles in an array to finally print it out

		printf("Random number that got generated this time was: %d\n", cp->random_number );
		fprintf(fnew,"Random number that got generated this time was: %d\n", cp->random_number );

		printf("Number of instruction cycles executed before the crash: %llu\n",cp->instr_cycles);
		fprintf(fnew,"Number of instruction cycles executed before the crash: %llu\n",cp->instr_cycles);
	
		//printf("Number of successful program runs before the crash: %llu\n",cp->program_runs);
		printf("Time of crash number %d is %ld seconds since January 1, 1970\n",cp->crash, crash_time);
	    fprintf(fnew,"Time of crash number %d is %ld seconds since January 1, 1970\n",cp->crash, crash_time);

		printf("At crash %d,time since the beginning of program execution is: %ld (in seconds)\n", cp->crash,(crash_time-start_seconds));
		fprintf(fnew,"At crash %d,time since the beginning of program execution is: %ld (in seconds)\n", cp->crash,(crash_time-start_seconds));
		//cp->crash_time_array[cp->crash] = (crash_time-start_seconds);

		cp->crash_time_array[cp->crash] = (crash_time-start_seconds);
		
		printf("\ncp->crash_time_array[%d]:%ld\n",cp->crash,cp->crash_time_array[cp->crash]);
		fprintf(fnew,"\ncp->crash_time_array[%d]:%ld\n",cp->crash,cp->crash_time_array[cp->crash]);

//**********************Reset conditions after mem crash*******************************
		reset_after_crash(r2,  program_memory, program_memory_encoded,  cp, start_seconds, fnew, fPC, finstr, i1);


return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


int report_error(struct crash_parameters *cp, struct registers *r2, struct instructions *i1, int program_memory[], FILE *fnew)
{
		
		if(cp->incorrect_data_flag ==1) //If error is due to incorrect data, save the cycles in his array. This saves only the cycle at which the first error occured
		{
			printf("PC value (in hex)=%x, instruction opcode being executed (in hex)=%x\n", (r2-> PC), program_memory[ (r2-> PC)]);
			fprintf(fnew,"PC value (in hex)=%x, instruction opcode being executed (in hex)=%x\n", (r2-> PC), program_memory[ (r2-> PC)]);

			cp->first_error_at_instr[cp->first_error] = cp->instr_cycles_for_error; //Save the cycles in an array to finally print it out
			cp->first_error= (cp->first_error)+1;
			cp->incorrect_data_flag=0; //reset

		}
		else
		{
			printf("PC value (in hex)=%x, erroneous instruction was (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], cp->erroneous_instruction );
			fprintf(fnew,"PC value (in hex)=%x, erroneous instruction was (in hex) = %x\n", cp-> random_mem[(cp->mem_count)-1], cp->erroneous_instruction);

			printf("The bit that has got flipped is: %d\n", cp->random_bit_mem );
			fprintf(fnew,"The bit that has got flipped is: %d\n", cp->random_bit_mem);

			cp->rest_of_the_errors[cp->other_errors] = cp->instr_cycles_for_error; //Save the cycles in an array to finally print it out
			cp->other_errors= (cp->other_errors)+1;
		}
		
		

		printf("Number of instruction cycles executed before the error: %llu\n\n",cp->instr_cycles_for_error);
		fprintf(fnew, "Number of instruction cycles executed before the error: %llu\n\n",cp->instr_cycles_for_error);

		cp->errors_so_far=cp->first_error+cp->other_errors;
		printf("******Unique errors so far= %d. Repeated errors are counted but not printed******\n",cp->errors_so_far);
		fprintf(fnew,"******Unique errors so far= %d. Repeated errors are counted but not printed******\n",cp->errors_so_far);
		//cp->first_error = 1;


return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int reset_after_crash(struct registers *r2,  int program_memory[], int program_memory_encoded[],struct crash_parameters *cp, time_t start_seconds, FILE *fnew, FILE *fPC, FILE *finstr, struct instructions *i1)

{

	int i=0, ii=0;

		cp->instr_cycles=0; //Reset instruction cycles after every crash


		//Reset program counter to beginning of the program
        reset_PC_to_beginninng(r2, fnew, cp, program_memory, program_memory_encoded, start_seconds, i1, fPC, finstr);
		//this flag will be used in main() not to increment PC in the cycle just after crash..so that the PC will not get increment without actually going through the fetch(), decode() steps

		cp->just_reset_PC_after_crash=1; 

		printf("***PC reset after crash***\n");
		fprintf(fnew,"***PC reset after crash***\n");

		printf("PC is reset to its initial values (in hex): PCL=%x, PCLATH=%x, PC=%x\n",r2->PCL, r2->PCLATH, r2->PC);
		fprintf(fnew,"PC is reset to its initial values (in hex): PCL=%x, PCLATH=%x, PC=%x\n",r2->PCL, r2->PCLATH, r2->PC);

		//clear all registers
		for(ii=0;ii<REG_MAX;++ii)
            r2->GP_Reg[i]=0; //clear all registers in register file map

		printf("***All general purpose registers reset after crash***\n");
		fprintf(fnew,"***All general purpose registers reset after crash***\n");

		//Reset program memory
		for(ii=0;ii< PROGRAM_MEM_SIZE; ++ii)
			program_memory[ii]=0;
		printf("***Program memory reset after crash***\n");
		fprintf(fnew,"***Program memory reset after crash***\n");

		//Load instructions back to program memory after crash
	      //	read_instr_from_file(fPC, finstr,program_memory,r2,fnew); //this is for add program

		//this is for matrix multiplication program
		fprintf(fnew,"***Reloading instructions to program memory***\n");
		read_PC_array_for_matrix_mult(fPC,program_memory,r2,fnew);
		read_instr_for_matrix_mult(finstr,program_memory,program_memory_encoded,r2,fnew);

return 0;

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

